/**
 *
 */
package ua.at.tsvetkov.samizdat.data;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

import ua.at.tsvetkov.net.NetCheck;
import ua.at.tsvetkov.samizdat.Const;
import ua.at.tsvetkov.samizdat.R;
import ua.at.tsvetkov.samizdat.activities.AcTemplate;
import ua.at.tsvetkov.strings.Util;
import ua.at.tsvetkov.ui.ProgressManager;
import ua.at.tsvetkov.util.Log;
import android.app.ProgressDialog;

/**
 * Класс читающий книгу по строке запроса.
 * 
 * @author A.Tsvetkov 2011, http://tsvetkov.at.ua, al@ukr.net
 */
public class BookDownloader {

	private static final String		ENCODING				= "windows-1251";
	private static final String		CR						= "\n";
	private static final int			KB						= 1024;
	// private static final int			DEFAULT_LINE_SIZE	= 100;
	private ArrayList<CharSequence>	mCache;
	private ProgressDialog				progress;
	private String							urlStr;
	private AcTemplate					context;
	private String							fileName;
	private CharSequence					header;
	private int								inetSize;
	private File							file;
	protected int							currentPosition;
	private int								lineCount;

	/**
	 * Инициализирует класс загрузки данных.
	 * 
	 * @param context текущий контекст
	 * @param urlStr строка для загрузки в интернете
	 * @param size размер в килобайтах
	 */
	public BookDownloader(AcTemplate context, Book book, ProgressDialog progress) {
		this.progress = progress;
		this.context = context;
		this.urlStr = book.getUrl();
		this.inetSize = book.getSize();
		this.fileName = book.getFileName();
		this.file = new File(fileName);
		lineCount = 0;
		mCache = new ArrayList<CharSequence>();
	}

	/**
	 * Загрузка данных из интернета на карту.
	 * 
	 * @param clean производить очистку строк от мусора
	 * @param reload производить обязательную перезагрузку из интернета
	 */
	public boolean download(boolean clean, boolean reload) {
		boolean isOld = System.currentTimeMillis() - file.lastModified() > Const.LIVE_TIME;
		if (file.exists() && file.length() > 0 && (!reload || isOld)) {
			return loadFromSD();
		}
		boolean result = false;
		if (NetCheck.getInstance().isOnline() && urlStr != null && urlStr.length() > 0) {
			result = loadDataFromInetAndSave(clean, reload);
			if (result)
				result = loadFromSD();
		}
		return result;
	}

	/**
	 * Загрузка данных из интернета.
	 * 
	 * @param fileName
	 * @param clean
	 * @param reload
	 */
	private boolean loadDataFromInetAndSave(boolean clean, boolean reload) {
		Log.v("Try download url=" + urlStr);
		ProgressManager pm = new ProgressManager(context, progress, context.getString(R.string.loading_from_internet), inetSize, 100);
		pm.setTitleAndMessage(context.getString(R.string.loading), context.getString(R.string.loading_from_internet));
		BufferedReader in = null;
		InputStream is = null;
		InputStreamReader br = null;
		BufferedWriter out = null;
		try {
			HttpURLConnection connection;
			URL url = new URL(urlStr);
			connection = (HttpURLConnection) url.openConnection();
			connection.setConnectTimeout(Const.TIMEOUT);
			connection.setRequestMethod("GET");
			connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
			connection.setRequestProperty("User-Agent", "Android reader");
			is = connection.getInputStream();
			br = new InputStreamReader(is, ENCODING);
			in = new BufferedReader(br);
			out = new BufferedWriter(new FileWriter(file));
			CharSequence stOld = in.readLine();
			// Очистка строки заголовка
			header = stOld;
			String[] sts = ((String) header).split("\\|");
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < sts.length; i++) {
				sts[i] = sts[i].trim();
				if (sts[i].length() == 0) {
					sts[i] = " ";
				}
				if (i == Data.HEADER_TITLE) {
					sts[i].replace(":", "").replace("?", "").replace("*", "");
				}
				sb.append(sts[i] + '|');
			}
			header = sb.toString() + urlStr;
			out.write(header + CR); // Запись заголовка
			lineCount = 0;
			int stSize = 0;
			while (true) {
				SoftReference<String> ref = new SoftReference<String>(in.readLine());
				if (ref.get() == null)
					break;
				stSize = ref.get().length();
				CharSequence st = Util.removeHtmlTag(ref.get().trim());
				pm.increment(((float) stSize) / KB);
				if (!(st.length() == 0 && stOld.length() == 0)) {
					out.write(st + CR);
					// putString(st);
					lineCount++;
				}
				stOld = st;
			}
			in.close();
			br.close();
			is.close();
			out.flush();
			out.close();
			Log.v("Loaded and saved " + urlStr);
		} catch (Exception e) {
			Log.e("Failed loading " + urlStr, e);
			try {
				out.flush();
				out.close();
			} catch (IOException e1) {
				Log.e("Failed closing " + file.getName(), e1);
			}
			pm.remove();
			return false;
		}
		return true;
	}

	// /**
	// * Загрузка данных с карты.
	// *
	// * @param true если загрузка успешная
	// */
	// public boolean loadFromSD(int position) {
	// int min = 0;
	// int max = casheSize * 2;
	// if (position != 0) {
	// min = position - casheSize;
	// if (min < 0)
	// min = 0;
	// max = position + casheSize;
	// if (max > lineCount)
	// max = lineCount;
	// }
	// BufferedReader in = null;
	// try {
	// in = new BufferedReader(new FileReader(file));
	// String st = "";
	// st = in.readLine();
	// header = st;
	// urlStr = getHeader()[Data.HEADER_URL];
	// int currentLine = 0;
	// while (in.ready()) {
	// st = in.readLine();
	// if (currentLine > max)
	// break;
	// if (currentLine > min)
	// mCache.add(st);
	// // putString(currentLine, st);
	// currentLine++;
	// }
	// in.close();
	// } catch (Exception e) {
	// Log.w("Failed loading " + fileName, e);
	// return false;
	// }
	// return true;
	// }

	/**
	 * Загрузка данных с карты.
	 * 
	 * @param true если загрузка успешная
	 */
	public boolean loadFromSD() {
		Log.v("Загрузка книги =" + fileName);
		ProgressManager pm = new ProgressManager(context, progress, context.getString(R.string.loading_from_internet), (int) (file.length() / KB), 100);
		pm.setTitleAndMessage(context.getString(R.string.loading), context.getString(R.string.loading_from_internet));
		BufferedReader in = null;
		try {
			in = new BufferedReader(new FileReader(file));
			header = in.readLine();
			urlStr = getHeader()[Data.HEADER_URL];
			lineCount = 0;
			while (in.ready()) {
				SoftReference<CharSequence> st = new SoftReference<CharSequence>(in.readLine());
				putString(st.get());
				lineCount++;
				// putString(lineCount++, st);
				pm.increment(((float) st.get().length()) / KB);
			}
			in.close();
			Log.v("Загружен " + fileName);
		} catch (Exception e) {
			Log.w("Failed loading " + fileName, e);
			pm.remove();
			return false;
		}
		pm.remove();
		return true;
	}

	public void clear() {
		mCache.clear();
		mCache = null;
	}

	public void putString(CharSequence value) {
		mCache.add(value);
	}

	public CharSequence getString(int key) {
		return mCache.get(key);
	}

	/**
	 * Возвращает количество строк в тексте
	 * 
	 * @return
	 */
	public int getLineCount() {
		return lineCount;
	}

	/**
	 * Возвращает url к произведениям автора
	 * 
	 * @return
	 */
	public String getAuthorUrl() {
		if (header == null || header.length() < 1)
			return "";
		int start = ((String) header).indexOf("object=") + 7;
		int end = ((String) header).lastIndexOf("/") + 1;
		String st = ((String) header).substring(start, end);
		return Const.URL_RAZDEL + st + "&order=title";
	}

	/**
	 * Возвращает url книги на сайте
	 * 
	 * @return
	 */
	public String getBookUrl() {
		return urlStr;
	}

	/**
	 * Возвращает строку заголовка книги
	 * 
	 * @return
	 */
	public CharSequence getHeaderString() {
		return header;
	}

	/**
	 * Возвращает поля заголовка книги
	 * 
	 * @return
	 */
	public String[] getHeader() {
		return ((String) header).split("\\|");
	}

}
